#include "stdafx.h"
#include "../Resource.h"
#include "../Injector/Injector.h"
#include "Application.h"

#include <AtlBase.h>
#include <AtlConv.h>


k_Application::k_Application(HINSTANCE ah_Instance, int ai_CmdShow)
	: mh_Instance(ah_Instance)
	, mi_CmdShow(ai_CmdShow)
	, mk_Environment(ah_Instance)
{
}


k_Application::~k_Application()
{
}


int k_Application::Run()
{
	this->PrepareRegistry();
	this->CreateDirectories();

    WNDCLASSEX wincl;        /* Data structure for the windowclass */ 

    /* The Window structure */ 
    wincl.hInstance = mh_Instance; 
    wincl.lpszClassName = "Walhall StartupTool"; 
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */ 
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */ 
    wincl.cbSize = sizeof (WNDCLASSEX); 

    /* Use default icon and mouse-pointer */ 
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); 
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); 
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW); 
    wincl.lpszMenuName = NULL;                 /* No menu */ 
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */ 
    wincl.cbWndExtra = 0;                      /* structure or the window instance */ 
    /* Use Windows's default color as the background of the window */ 
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; 

    /* Register the window class, and if it fails quit the program */ 
    if (!RegisterClassEx (&wincl)) 
        return 0; 

    /* The class is registered, let's create the program*/ 
    mh_Handle = CreateWindowEx ( 
           0,                   /* Extended possibilites for variation */ 
           "Walhall StartupTool",         /* Classname */ 
           "Walhall",       /* Title Text */ 
           WS_OVERLAPPEDWINDOW, /* default window */ 
           CW_USEDEFAULT,       /* Windows decides the position */ 
           CW_USEDEFAULT,       /* where the window ends up on the screen */ 
           0,                 /* The programs width */ 
           0,                 /* and height in pixels */ 
           HWND_DESKTOP,        /* The window is a child-window to desktop */ 
           NULL,                /* No menu */ 
           mh_Instance,       /* Program Instance handler */ 
           NULL                 /* No Window Creation data */ 
           ); 

	this->CreateNotifyIcon();
	::Shell_NotifyIcon(NIM_ADD, &mr_NotificationData);

	this->StartInjection();

    /* Run the message loop. It will run until GetMessage() returns 0 */ 
	MSG msg = { 0 };
	while(msg.message != WM_QUIT)
	{
		if(GetMessage(&msg,NULL,0,0))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	::Shell_NotifyIcon(NIM_DELETE, &mr_NotificationData);

	// Uninject
	this->EndInjection();

	return 0;
}

static HMENU gh_ContextMenu = NULL;

LRESULT CALLBACK k_Application::WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    switch (message)
    { 
		case WM_LBUTTONDOWN:

		case WM_CREATE:
			gh_ContextMenu = CreatePopupMenu();
			InsertMenu(gh_ContextMenu, 0, MF_BYPOSITION, 2, "&Exit");
			InsertMenu(gh_ContextMenu, 0, MF_BYPOSITION | MF_SEPARATOR, 0, "");
			InsertMenu(gh_ContextMenu, 0, MF_BYPOSITION, 1, "&About Walhall 0.12");
			break;

		case WM_COMMAND:
			if (wParam == 1)
			{
				MessageBox(hwnd, "Walhall Alpha 0.12 (2007-2008)\n\nBy:\nMark Leutloff\nSev\n\nMail: Mark@Dras.biz", "About Walhall", MB_OK);
			}
			else if (wParam == 2)
			{
				DestroyMenu(gh_ContextMenu); 
				PostQuitMessage(0);
			}
			break;

		case UM_NOTIFY:
			if (lParam == WM_RBUTTONDOWN)
			{
				POINT lr_Point;
				::GetCursorPos(&lr_Point);

				SetForegroundWindow(hwnd);
				TrackPopupMenu (gh_ContextMenu, TPM_CENTERALIGN | TPM_LEFTBUTTON, lr_Point.x, lr_Point.y, 0, hwnd, 0);
				PostMessage(hwnd, WM_NULL, 0, 0);
			}
			break;
        case WM_DESTROY:
			DestroyMenu(gh_ContextMenu); 
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}


void k_Application::CreateNotifyIcon()
{
	// zero the structure - note: Some Windows funtions
	// require this but I can't be bothered to remember
	// which ones do and which ones don't.
	ZeroMemory(&mr_NotificationData,sizeof(NOTIFYICONDATA));

	mr_NotificationData.cbSize = NOTIFYICONDATA_V1_SIZE;

	// the ID number can be any UINT you choose and will
	// be used to identify your icon in later calls to
	// Shell_NotifyIcon
	mr_NotificationData.uID = IDI_ICON1;

	// state which structure members are valid
	// here you can also choose the style of tooltip
	// window if any - specifying a balloon window:
	// NIF_INFO is a little more complicated 
	mr_NotificationData.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;

	// load the icon note: you should destroy the icon
	// after the call to Shell_NotifyIcon
	mr_NotificationData.hIcon =
		(HICON)LoadImage(mh_Instance,
			MAKEINTRESOURCE(IDI_ICON1),
			IMAGE_ICON,
			GetSystemMetrics(SM_CXSMICON),
			GetSystemMetrics(SM_CYSMICON),
			LR_DEFAULTCOLOR);

	// set the window you want to recieve event messages
	mr_NotificationData.hWnd = mh_Handle;

	// set the message to send
	// note: the message value should be in the
	// range of WM_APP through 0xBFFF
	mr_NotificationData.uCallbackMessage = UM_NOTIFY;
}


void k_Application::StartInjection()
{
	std::wstring ls_DllPath = mk_Environment.get_ModulePath() + L"Parasite.dll";
	HMODULE lh_Module = ::LoadLibraryW(ls_DllPath.c_str());
	if (lh_Module != NULL)
	{
		typeBaseFunc l_InstallHook_ = (typeBaseFunc)::GetProcAddress(lh_Module, "InstallHooks");
		if (l_InstallHook_ != NULL)
			l_InstallHook_();
	}
}


void k_Application::EndInjection()
{
	std::wstring ls_DllPath = mk_Environment.get_ModulePath()+L"Parasite.dll";
	HMODULE lh_Module = ::LoadLibraryW(ls_DllPath.c_str());
	if (lh_Module != NULL)
	{
		typeBaseFunc l_UnInstallHook_ = (typeBaseFunc)::GetProcAddress(lh_Module, "RemoveHooks");
		if (l_UnInstallHook_ != NULL)
			l_UnInstallHook_();
	}
}


void k_Application::PrepareRegistry()
{
	HKEY lh_OpenedKey;
	if (::RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Walhall\\Walhall", 0, KEY_ALL_ACCESS, &lh_OpenedKey) != S_OK)
	{
		if (S_OK != ::RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Walhall\\Walhall", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &lh_OpenedKey, 0))
			return;
	}
	
	std::wstring ls_PathW = mk_Environment.get_ModulePath();
	USES_CONVERSION;
	std::string ls_PathA = W2A(ls_PathW.c_str());
	::RegSetValueEx(lh_OpenedKey, "WalhallPath", NULL, REG_SZ, (CONST BYTE*)ls_PathA.c_str(), (DWORD)ls_PathA.size());

	::RegCloseKey(lh_OpenedKey);
}


void k_Application::CreateDirectories()
{
	std::wstring ls_WalhallAppDir = mk_Environment.get_AppDataDirectory() + L"Walhall\\";
	::CreateDirectoryW(ls_WalhallAppDir.c_str(), NULL);
	ls_WalhallAppDir += L"Walhall\\";
	::CreateDirectoryW(ls_WalhallAppDir.c_str(), NULL);
}
